package com.nb.sdk;


import com.alibaba.fastjson.JSONObject;
import com.nb.sdk.util.Md5Util;

import java.io.*;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 客户端默认实现，
 * 实际需要用户自己初始化Client，设置这些参数
 */
public class DefaultClient implements Client {

    //默认域名
    private static final String SERVICE_URL = "http://127.0.0.1/";

    /**
     * 客户端应用appId
     */
    private String appId;
    /**
     * 客户端应用秘钥
     */
    private String appSecret;
    /**
     * 服务端接口域名
     */
    private String apiDomain;


    /**
     * 接口版本号
     */
    public static final String apiVersion = "1.0";

    /**
     * 接口超时时间
     */
    private int timeout = 30000;


    public DefaultClient(String appId, String appSecret, String apiDomain) {
        this.appId = appId;
        this.appSecret = appSecret;
        this.apiDomain = apiDomain;
        this.timeout = timeout;
    }

    @Override
    public void setTimeout(int paramInt) {
        this.timeout = paramInt;
    }

    /**
     * 执行逻辑
     *
     * @param methodName
     * @param args
     * @param returnType
     * @return
     * @throws NbSdkException
     * @throws IOException
     */
    @Override
    public Object execute(String methodName, Object[] args, Type returnType) throws NbSdkException, IOException {
        String path = apiDomain + "/" + methodName;
        System.out.println("请求URL=" + path);

        //方法参数暂时只取第一个，默认一个参数
        String body = JSONObject.toJSONString(args[0]);
        System.out.println("请求参数="+body);


        HttpURLConnection conn = null;
        OutputStream out = null;
        InputStream in = null;
        String result = "";
        try {
            //发起http请求
            URL url = new URL(path);
            conn = (HttpURLConnection) url.openConnection();
            //建立socket连接超时时间
            conn.setConnectTimeout(timeout);
            //读数据超时时间
            conn.setReadTimeout(timeout);
            conn.setRequestMethod("POST");
            // 设置传送的内容类型是json格式
            conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
            // 接收的内容类型也是json格式
            conn.setRequestProperty("Accept", "application/json;charset=utf-8");

            System.err.println("生成签名:"+appId+appSecret+body);
            String sign = Md5Util.getMd5(appId+appSecret+body);
            conn.setRequestProperty("appId", appId);
            conn.setRequestProperty("sign", sign);
            // 由于URLConnection在默认的情况下不允许输出，所以在请求输出流之前必须调用setDoOutput(true)。为一个HTTP URL将doOutput设置为true时，请求方法将由GET变为POST
            conn.setDoOutput(true);
            // 返回一个OutputStream，可以用来写入数据传送给服务器
            out = conn.getOutputStream();
            out.write(body.getBytes(StandardCharsets.UTF_8));
            out.flush();
            //建立连接
            conn.connect();
            //判断数字响应码是否是200
            int responseCode = conn.getResponseCode();


            // 获取输入流
            in = conn.getInputStream();
            // 获取返回的内容
            StringWriter sw = new StringWriter();
            InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
            char[] buffer = new char[4096];
            for (int n = 0; -1 != (n = reader.read(buffer)); ) {
                sw.write(buffer, 0, n);
            }
            result = sw.toString();
            System.out.println("http返回结果:" + result);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
            if (out != null) {
                out.close();
            }
            if (in != null) {
                in.close();
            }

        }
        //解码
        JSONObject jsonObject = JSONObject.parseObject(result);
        int status = jsonObject.getInteger("status");
        if(status != 200){
            //业务异常
            String msg = jsonObject.getString("msg");
            throw new NbSdkException(status, msg);
        }else{
            //正常响应
            if (returnType.equals(void.class) || returnType.equals(Void.class)){
                return null;
            }
            Object data = jsonObject.getObject("data", returnType);
            return data;
            //TODO:分页等不同格式尝试
        }

    }







    public static String getServiceUrl() {
        return SERVICE_URL;
    }

    public static String getApiVersion() {
        return apiVersion;
    }

    public String getAppId() {
        return appId;
    }

    public void setAppId(String appId) {
        this.appId = appId;
    }

    public String getAppSecret() {
        return appSecret;
    }

    public void setAppSecret(String appSecret) {
        this.appSecret = appSecret;
    }

    public String getApiDomain() {
        return apiDomain;
    }

    public void setApiDomain(String apiDomain) {
        this.apiDomain = apiDomain;
    }

    public int getTimeout() {
        return timeout;
    }

}
